_require "../../../../basis.smi"
_require "../../../../smlformat-lib.smi"
_require "../../../data/symbols/main/Loc.smi"
_require "../../../data/symbols/main/Symbol.smi"
_require "../../../libs/ids/main/LocalID.smi"
_require "../../../data/symbols/main/RecordLabel.smi"
_require "../../../data/name/main/CodeLabel.smi"
_require "../../../data/types/main/Types.ppg.smi"
_require "../../../data/runtimetypes/main/FFIAttributes.ppg.smi"
_require "../../../data/builtin/main/BuiltinPrimitive.ppg.smi"
_require local "../../../compilerIRs/absyn/main/ConstFormat.smi"

structure TypedLambda =
struct

  type loc = Loc.loc
  type ty = Types.ty
  type btvEnv = Types.btvEnv
  type varInfo = {path : Symbol.longsymbol, id : VarID.id, ty : ty}
  type exVarInfo = Types.exVarInfo
  datatype cast = datatype BuiltinPrimitive.cast

  type primTy =
      {boundtvars : Types.btvEnv, argTyList : ty list, resultTy : ty}
  type primInfo =
      {primitive : BuiltinPrimitive.primitiveTypedLambda, ty : primTy}

  datatype tlint =
      INT8 of Int8.int
    | INT16 of Int16.int
    | INT32 of Int32.int
    | INT64 of Int64.int
    | WORD8 of Word8.word
    | WORD16 of Word16.word
    | WORD32 of Word32.word
    | WORD64 of Word64.word
    | CONTAG of Word32.word
    | CHAR of Char.char

  datatype tlconst =
      REAL64 of Real64.real
    | REAL32 of Real32.real
    | UNIT
    | NULLPOINTER
    | NULLBOXED
    | FOREIGNSYMBOL of {name : string, ty : ty}

  datatype tlstring =
      STRING of string
    | INTINF of IntInf.int

  datatype tlexp =
      TLCONSTANT of tlconst * loc
    | TLINT of tlint * loc
    | TLSTRING of tlstring * loc
    | TLVAR of varInfo * loc
    | TLEXVAR of exVarInfo * loc
    | TLFNM of
      {
        argVarList : varInfo list,
        bodyTy : ty,
        bodyExp : tlexp,
        loc : loc
      }
    | TLAPPM of
      {
        funExp : tlexp,
        funTy : ty,
        argExpList : tlexp list,
        loc : loc
      }
    | TLSWITCH of
      {
        exp : tlexp,
        expTy : ty,
        branches : {const : tlint, body : tlexp} list,
        defaultExp : tlexp,
        resultTy : ty,
        loc : loc
      }
    | TLDYNAMICEXISTTAPP of
      {
        existInstMap : tlexp,
        exp : tlexp,
        expTy : ty,
        instTyList : ty list,
        loc : loc
      }
    | TLPRIMAPPLY of
      {
        primOp : primInfo,
        instTyList : ty list,
        argExpList : tlexp list,
        loc : loc
      }
    | TLOPRIMAPPLY of
      {
       oprimOp : Types.oprimInfo,
       instTyList : ty list,
       argExp : tlexp,
       loc : loc
      }
    | TLRECORD of
      {
        fields : tlexp RecordLabel.Map.map,
        recordTy : ty RecordLabel.Map.map,
        loc : loc
      }
    | TLSELECT of
      {
        label : RecordLabel.label,
        recordExp : tlexp,
        recordTy : ty,
        resultTy : ty,
        loc : loc
      }
    | TLMODIFY of
      {
        label : RecordLabel.label,
        recordExp : tlexp,
        recordTy : ty,
        elementExp : tlexp,
        elementTy : ty,
        loc : loc
      }
    | TLLET of
      {
        decl : tldecl,
        body : tlexp,
        loc : loc
      }
    | TLRAISE of
      {
        exp : tlexp,
        resultTy : ty,
        loc : loc
      }
    | TLHANDLE of
      {
        exp : tlexp,
        exnVar : varInfo,
        handler : tlexp,
        resultTy : ty,
        loc : loc
      }
    | TLTHROW of
      {
        catchLabel : FunLocalLabel.id,
        argExpList : tlexp list,
        resultTy : ty,
        loc : loc
      }
    | TLCATCH of
      {
        catchLabel : FunLocalLabel.id,
        argVarList : varInfo list,
        catchExp : tlexp,
        tryExp : tlexp,
        resultTy : ty,
        loc : loc
      }
    | TLPOLY of
      {
        btvEnv : btvEnv,
        constraints : Types.constraint list,
        expTyWithoutTAbs : ty,
        exp : tlexp,
        loc : loc
      }
    | TLTAPP of
      {
        exp : tlexp,
        expTy : ty,
        instTyList : ty list,
        loc : loc
      }
    | TLFOREIGNAPPLY of
      {
        funExp : tlexp,
        argExpList : tlexp list,
        attributes : FFIAttributes.attributes,
        resultTy : ty option,
        loc : loc
      }
    | TLCALLBACKFN of
      {
        attributes : FFIAttributes.attributes,
        argVarList : varInfo list,
        bodyExp : tlexp,
        resultTy : ty option,
        loc : loc
      }
    | TLCAST of
      {
        exp : tlexp,
        expTy : ty,
        targetTy : ty,
        cast : cast,
        loc : loc
      }
    | TLSIZEOF of
      {
        ty : ty,
        loc : loc
      }
    | TLINDEXOF of
      {
        recordTy : ty,
        label : RecordLabel.label,
        loc : loc
      }
    | TLREIFYTY of
      {
        ty : ty,
        loc : loc
      }

  and tldecl =
      TLVAL of
      {
        var : varInfo,
        exp : tlexp,
        loc : loc
      }
    | TLVALREC of {var:varInfo, exp:tlexp} list * loc
    | TLVALPOLYREC of
      {
        btvEnv : btvEnv,
        constraints : Types.constraint list,
        recbinds : {var:varInfo, exp:tlexp} list,
        loc : loc
      }
    | TLEXPORTVAR of
      {
        weak : bool,
        var : exVarInfo,
        exp : tlexp
      }
    | TLEXTERNVAR of exVarInfo * Types.provider

  val format_varInfo : varInfo -> SMLFormat.format
  val formatWithType_varInfo : varInfo -> SMLFormat.format
  val format_primInfo : primInfo -> SMLFormat.format
  val formatWithType_primInfo : primInfo -> SMLFormat.format
  val format_tlint : tlint -> SMLFormat.format
  val formatWithType_tlint : tlint -> SMLFormat.format
  val format_tlconst : tlconst -> SMLFormat.format
  val formatWithType_tlconst : tlconst -> SMLFormat.format
  val format_tlstring : tlstring -> SMLFormat.format
  val formatWithType_tlstring : tlstring -> SMLFormat.format
  val format_tlexp : tlexp -> SMLFormat.format
  val formatWithType_tlexp : tlexp -> SMLFormat.format
  val format_tldecl : tldecl -> SMLFormat.format
  val formatWithType_tldecl : tldecl -> SMLFormat.format

end
